import { Dictionary } from "../Resource/ResourceData";


export class TweenExt {


    private static s_tweenUIscalList:Array<Laya.UIComponent>=[];
    private static s_tweenRotationscalList:Array<Laya.UIComponent>=[];
    private static s_tweenUIposList:Array<Laya.UIComponent>=[];
    
    private static s_viewUIList:Array<Laya.View>=[];
    private static s_tweenSprite3DScalList:Array<Laya.Sprite3D>=[];
    private static s_tweenSprite3DPosList:Array<Laya.Sprite3D>=[];

    public static Init() {
        // for (const key in TweenExt) {
        //     if (key === "init") continue
        //     laya.utils.Tween.prototype[key] = TweenExt[key];
        // }

        Laya.Tween.prototype["_initProps"] = TweenExt["_initProps"];
        Laya.Tween.prototype["_updateEase"] = TweenExt["_updateEase"];
        Laya.Tween.prototype["complete"] = TweenExt["complete"];
        Laya.Tween.prototype["completData"] = TweenExt["completData"];
    }
    private static _initProps(target, props, isTo) {
        for (let p in props) {
            if ((typeof (target[p]) == 'number')) {
                let start = isTo ? target[p] : props[p];
                let end = isTo ? props[p] : target[p];
                this["_props"].push([p, start, end - start]);
                if (!isTo) target[p] = start;
            }
            if (target[p] instanceof Laya.Vector4) {
                let v4_lerp = new Laya.Vector4();
                let v4_start = isTo ? target[p].clone() : props[p];
                let v4_end = isTo ? props[p] : target[p].clone();
                if (!(v4_start instanceof Laya.Vector4)) {
                    v4_start = new Laya.Vector4(v4_start.x, v4_start.y, v4_start.z, v4_start.w);
                }
                v4_end = new Laya.Vector4(v4_end.x, v4_end.y, v4_end.z, v4_end.w);
                Laya.Vector4.subtract(v4_end, v4_start, v4_lerp);
                this["_props"].push([p, v4_start, v4_lerp, v4_end]);
                if (!isTo) target[p] = v4_start;
            }
            if (target.transform && target.transform[p] instanceof Laya.Vector3) {
                let v3_lerp = new Laya.Vector3();
                let v3_start = isTo ? target.transform[p].clone() : props[p];
                let v3_end = isTo ? props[p] : target.transform[p].clone();
                if (!(v3_start instanceof Laya.Vector3)) {
                    v3_start = new Laya.Vector3(v3_start.x, v3_start.y, v3_start.z);
                }
                v3_end = new Laya.Vector3(v3_end.x, v3_end.y, v3_end.z);
                Laya.Vector3.subtract(v3_end, v3_start, v3_lerp);

                this["_props"].push([p, v3_start, v3_lerp, v3_end]);
                if (!isTo) target[p] = v3_start;
            }
        }
    }
    private static _updateEase(time: number) {
        var target = this["_target"];
        if (!target) return;
        if (target.destroyed) return this["clearTween"](target);
        var usedTimer = this["_usedTimer"] = time - this["_startTimer"] - this["_delay"];
        if (usedTimer < 0) return;
        if (usedTimer >= this["_duration"]) return this["complete"]();
        var ratio = usedTimer > 0 ? this["_ease"](usedTimer, 0, 1, this["_duration"]) : 0;
        var props = this["_props"];
        for (var i = 0, n = props.length; i < n; i++) {
            var prop = props[i];
            //对象的
            if (typeof target[prop[0]] === "number") {
                target[prop[0]] = prop[1] + (ratio * prop[2]);
            }
            //3d的

            if (target[prop[0]] instanceof Laya.Vector4) {
                let x = prop[1].x + (ratio * prop[2].x);
                let y = prop[1].y + (ratio * prop[2].y);
                let z = prop[1].z + (ratio * prop[2].z);
                let w = prop[1].w + (ratio * prop[2].w);
                target[prop[0]] = new Laya.Vector4(
                    x,
                    y,
                    z,
                    w);
            }
            if (target[prop[0]] instanceof Laya.Vector3) {
                let x = prop[1].x + (ratio * prop[2].x);
                let y = prop[1].y + (ratio * prop[2].y);
                let z = prop[1].z + (ratio * prop[2].z);
                target[prop[0]] = new Laya.Vector3(
                    x,
                    y,
                    z);
            }
            if (target.transform && target.transform[prop[0]] instanceof Laya.Vector3) {
                let x = prop[1].x + (ratio * prop[2].x);
                let y = prop[1].y + (ratio * prop[2].y);
                let z = prop[1].z + (ratio * prop[2].z);
                target.transform[prop[0]] = new Laya.Vector3(
                    x,
                    y,
                    z);
            }
        }

        if (this["update"]) this["update"].run();
    }
    private static complete() {
        if (!this["_target"]) return;
        Laya.timer.runTimer(this, this["firstStart"]);
        var handler = this["_complete"];
        this.completData()
        if (this["update"]) this["update"].run();
        this["_count"]++;
        if (this["repeat"] != 0 && this["_count"] >= this["repeat"]) {
            this["clear"]();
            handler && handler.run();
        } else {
            this["restart"]();
        }
    }
    private static completData() {
        var target = this["_target"];
        var props = this["_props"];
        for (var i = 0, n = props.length; i < n; i++) {
            var prop = props[i];
            if (typeof target[prop[0]] === "number") {
                target[prop[0]] = prop[1] + prop[2];
            }
            if (target[prop[0]] instanceof Laya.Vector4) {
                target[prop[0]] = prop[3]
            }
            if (target[prop[0]] instanceof Laya.Vector3) {
                target[prop[0]] = prop[3]
            }
            if (target.transform && target.transform[prop[0]] instanceof Laya.Vector3) {
                target.transform[prop[0]] = prop[3];
            }
        }
    }

    //////////=================================UIView=======================================

    public static TweenViewScal(view:Laya.View,time=500,scalto=1,callback:Function=null)
    {
        let uinodeIndex=TweenExt.s_viewUIList.indexOf(view);
        if (uinodeIndex>-1) 
            return;

        TweenExt.s_viewUIList.push(view); 
        let callbackhandler=new Laya.Handler(this,TweenExt.TweenUIViewEnd,[view,callback]);
        Laya.Tween.to(view,{scaleX:1,scaleY:1},time,Laya.Ease.linearNone,callbackhandler);
    }

    private static TweenUIViewEnd(view,callback)
    {
        callback&&callback();
        let uinodeIndex=TweenExt.s_viewUIList.indexOf(view);
        if (uinodeIndex>-1) 
            TweenExt.s_viewUIList.splice(uinodeIndex,1);
        callback&&callback();
    }

    //////////=================================UINode========================================

    public static TweenUIPosX(view:Laya.UIComponent,posx:number,time=1000,callback:Function=null,esce:Function=Laya.Ease.linearNone)
    {  
        let uinodeIndex=TweenExt.s_tweenUIposList.indexOf(view);
        if (uinodeIndex>-1) 
            return;
        TweenExt.s_tweenUIposList.push(view); 
        let callbackhandler=new Laya.Handler(this,TweenExt.TweenUIPosEnd,[view,callback]); 
        Laya.Tween.to(view,{x:posx},time,esce,callbackhandler);
    }
    
    private static TweenUIPosEnd(node,callback)
    {
        let uinodeIndex=TweenExt.s_tweenUIposList.indexOf(node);
        if (uinodeIndex>-1) 
            TweenExt.s_tweenUIposList.splice(uinodeIndex,1);
        callback&&callback();
    }

//=========================================================Rotation====================================
    public static TweenUIRotationCycle(view:Laya.UIComponent,roattionto=70,rotationBack=0,time=500,callback:Function=null)
    {
        let uinodeIndex=TweenExt.s_tweenRotationscalList.indexOf(view);
        if (uinodeIndex>-1) 
            return;
        TweenExt.s_tweenRotationscalList.push(view); 
        let callbackhandler=new Laya.Handler(this,TweenExt.TweenUIRotationBack,[view,rotationBack,time,callback]);
        Laya.Tween.to(view,{rotation:roattionto},time,Laya.Ease.linearInOut,callbackhandler);
    }

    private static TweenUIRotationBack(view:Laya.UIComponent,roattionback:number,time,callback:Function=null)
    {
        let callbackhandler=new Laya.Handler(this,TweenExt.TweenRotationEnd,[view,callback]);
        Laya.Tween.to(view,{rotation:roattionback},time,Laya.Ease.linearNone,callbackhandler);
    }

    private static TweenRotationEnd(node,callback)
    {
        let uinodeIndex=TweenExt.s_tweenRotationscalList.indexOf(node);
        if (uinodeIndex>-1) 
            TweenExt.s_tweenRotationscalList.splice(uinodeIndex,1);
        callback&&callback();
    }


    //=====================================================
    
    public static TweenUIScal(view:Laya.UIComponent,scalto=1,time=1000,callback:Function=null,esce:Function=Laya.Ease.linearNone)
    {
        let uinodeIndex=TweenExt.s_tweenUIscalList.indexOf(view);
        if (uinodeIndex>-1) 
            return;
        TweenExt.s_tweenUIscalList.push(view); 
        let callbackhandler=new Laya.Handler(this,TweenExt.TweenEnd,[view,callback]);
        Laya.Tween.to(view,{scaleX:scalto,scaleY:scalto},time,esce,callbackhandler);
    }

    public static TweenUINodeScalCycle(node:Laya.UIComponent,time=50,scalnum=1.2,callback:Function=null)
    {
        let uinodeIndex=TweenExt.s_tweenUIscalList.indexOf(node);
        if (uinodeIndex>-1) 
            return;
        TweenExt.s_tweenUIscalList.push(node);
        let tscaleX=node.scaleX*scalnum;
        let tscaleY=node.scaleY*scalnum;
        
        let callbackhandler=new Laya.Handler(this,TweenExt.TweenUINodeBack,[node,time,scalnum,callback]);
        Laya.Tween.to(node,{scaleX:tscaleX,scaleY:tscaleY},time,Laya.Ease.linearNone,callbackhandler);
    }

    private static TweenUINodeBack(node:Laya.UIComponent,time,scalnum:number,callback:Function=null)
    {
        let tscaleX=node.scaleX/scalnum;
        let tscaleY=node.scaleY/scalnum;

        let callbackhandler=new Laya.Handler(this,TweenExt.TweenEnd,[node,callback]);
        Laya.Tween.to(node,{scaleX:tscaleX,scaleY:tscaleY},time,Laya.Ease.linearNone,callbackhandler);
    }

    private static TweenEnd(node,callback)
    {
        let uinodeIndex=TweenExt.s_tweenUIscalList.indexOf(node);
        if (uinodeIndex>-1) 
            TweenExt.s_tweenUIscalList.splice(uinodeIndex,1);
        callback&&callback();
    }

//========================================3d精灵===========================================
    public static Tween3DSprite(sprite3D:Laya.Sprite3D,time=50,scalnum=1.2,callback:Function=null)
    {
        let spriteIndex=TweenExt.s_tweenSprite3DScalList.indexOf(sprite3D);
        if (spriteIndex>-1) 
            return;
        TweenExt.s_tweenSprite3DScalList.push(sprite3D);
        let tscaleX=sprite3D.transform.scale.x*scalnum;
        let tscaleY=sprite3D.transform.scale.y*scalnum;
        let tscaleZ=sprite3D.transform.scale.z*scalnum;
        
        let callbackhandler=new Laya.Handler(this,TweenExt.Tween3DSpriteBack,[sprite3D,time,scalnum,callback]);
        Laya.Tween.to(sprite3D.transform,{scale:{x:tscaleX,y:tscaleY,z:tscaleZ} },time,Laya.Ease.linearNone,callbackhandler);
    }


    private static Tween3DSpriteBack(sprite3D:Laya.Sprite3D,time,scalnum,callback:Function=null)
    {
        let tscaleX=sprite3D.transform.scale.x/scalnum;
        let tscaleY=sprite3D.transform.scale.y/scalnum;
        let tscaleZ=sprite3D.transform.scale.z/scalnum;

        let callbackhandler=new Laya.Handler(this,TweenExt.Tween3DSprireEnd,[sprite3D,callback]);
        Laya.Tween.to(sprite3D.transform,{scale:{x:tscaleX,y:tscaleY,z:tscaleZ} },time,Laya.Ease.linearNone,callbackhandler);
    }


    private static Tween3DSprireEnd(node,callback)
    {
        let uinodeIndex=TweenExt.s_tweenSprite3DScalList.indexOf(node);
        if (uinodeIndex>-1) 
            TweenExt.s_tweenSprite3DScalList.splice(uinodeIndex,1);
        callback&&callback();
    }

    //=========================================3DPos==============================
    public static Tween3DSpritePos(sprite3D:Laya.Sprite3D,time=200,pos:Laya.Vector3,callback:Function=null)
    {
        let spriteIndex=TweenExt.s_tweenSprite3DPosList.indexOf(sprite3D);
        if (spriteIndex>-1) 
            return;
        TweenExt.s_tweenSprite3DPosList.push(sprite3D);   
        let callbackhandler=new Laya.Handler(this,TweenExt.Tween3DEnd,[sprite3D,callback]);
        Laya.Tween.to(sprite3D,{position:{x:pos.x,y:pos.y,z:pos.z} },time,Laya.Ease.linearNone,callbackhandler);
    }

    private  static Tween3DEnd(sp,callback)
    {
        let uinodeIndex=TweenExt.s_tweenSprite3DScalList.indexOf(sp);
        if (uinodeIndex>-1)  
            TweenExt.s_tweenSprite3DScalList.splice(uinodeIndex,1);
        else if (TweenExt.s_tweenSprite3DPosList.indexOf(sp))
            TweenExt.s_tweenSprite3DPosList.splice(uinodeIndex,1);
        callback&&callback();
    }


    public static Tween3DSpriteScal(sprite3D:Laya.Sprite3D,time=200,scalnum=1.2,callback:Function=null)
    {
        let spriteIndex=TweenExt.s_tweenSprite3DScalList.indexOf(sprite3D);
        if (spriteIndex>-1)  return;
        TweenExt.s_tweenSprite3DScalList.push(sprite3D);
        let tscaleX=scalnum;
        let tscaleY=scalnum;
        let tscaleZ=scalnum;
        
        let callbackhandler=new Laya.Handler(this,TweenExt.Tween3DEnd,[sprite3D,callback]);
        Laya.Tween.to(sprite3D,{scale:{x:tscaleX,y:tscaleY,z:tscaleZ} },time,Laya.Ease.linearNone,callbackhandler);
    }

}